package br.unifor.cct.mia.runner;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import br.unifor.cct.mia.coevolution.CoevolutionaryDomain;
import br.unifor.cct.mia.coevolution.InvalidTypeException;
import br.unifor.cct.mia.coevolution.evaluate.EvaluateUtils;
import br.unifor.cct.mia.coevolution.memory.SharedMemory;
import br.unifor.cct.mia.dataenhancement.Database;
import br.unifor.cct.mia.dataenhancement.GenotypeConverter;
import br.unifor.cct.mia.dataenhancement.Structure;
import br.unifor.cct.mia.dataenhancement.Tuple;
import br.unifor.cct.mia.evaluate.Evaluate;
import br.unifor.cct.mia.evaluate.classification.WekaClassification;
import br.unifor.cct.mia.evolutionary.Genotype;
import br.unifor.cct.mia.evolutionary.SpeciesConstants;
import br.unifor.cct.mia.ga.Ga;
import br.unifor.cct.mia.ga.coevolutionary.CoevGaFC;
import br.unifor.cct.mia.ga.coevolutionary.CoevGaFS;
import br.unifor.cct.mia.ga.coevolutionary.CoevGaIS;
import br.unifor.cct.mia.ga.coevolutionary.CoevGaMV;
import br.unifor.cct.mia.util.LoadFile;

public class Coevolutionary {

	public static String BASE_NAME = "soybeanReduzida";
	public static String DATASET_STRUCTURE = "./data/"+BASE_NAME+"_estrutura.txt";
	public static String DATASET_DATA = "./dataPart/"+BASE_NAME+"_TRAIN_data.txt";
	public static String DATASET_TESTE = "./dataPart/"+BASE_NAME+"_TEST_data.txt";
	public static String RESULT_SERIAL_FILE = "./results/result_"+BASE_NAME+".ser";
	
	public static Integer learnerType = Evaluate.J48;
	private static int nBits = 0;
	
	public static void main(String[] args) {
		
		Structure st = LoadFile.loadStructure(DATASET_STRUCTURE);
    	Database db = LoadFile.loadDatabase(DATASET_DATA);
		System.out.println("Arquivos carregados com sucesso");
				
		try {
			System.out.println(new Date());
			CoevolutionaryDomain domain = new CoevolutionaryDomain(CoevolutionaryDomain.MEMORY,learnerType);
			
			//Para MissinValue
        	//int total = (int)Math.round(db.size()*st.size()*0.10);
        	List positions = LoadFile.getFaultDatabase(st,db);
        	Tuple tuples = new Tuple();
        	db.mountStr(tuples, positions);
        	
        	domain.setTuples(tuples);
        	domain.setPositions(positions);
        	
            Ga gaMv = new CoevGaMV(st,db,domain,positions,positions.size(),tuples,null);			
			Ga gaFs = new CoevGaFS(db,st,domain,null);
			Ga gaIs = new CoevGaIS(db,st,domain,null);
			Ga gaFc = new CoevGaFC(db,st,domain,null);
			
			ArrayList species =  new ArrayList();
			species.add(gaMv);
			species.add(gaFs);
			species.add(gaIs);
			species.add(gaFc);
			
			domain.setSpecies(species);
			domain.start();
			
			domain.createResultFile("temp/resultado.txt",st,db,tuples,positions,nBits);
						
			
			//################# TESTES ###################
			/*ObjectOutput out = new ObjectOutputStream(new FileOutputStream(RESULT_SERIAL_FILE));
		    out.writeObject(domain.getBest());
		    out.close();*/			
			
			boolean testSetOnly = true;
		    WekaClassification classifier = new WekaClassification(learnerType,null);
		    //classifier.setTestType(ClassifierPanel.SUPPLIED_TEST_SET);
		    
		    GenotypeConverter converter = new GenotypeConverter();
		    
        	/** Calcula o fitness utilizando dataset de teste */        	        	
		    //Deve treinar com a base de dados de treinamento
		    SharedMemory bestMem = domain.getBest();	
		    Genotype fsGen = (Genotype)bestMem.getIndividual(SpeciesConstants.FEATURE_SELECTION).getIndividual();
        	//Arquivo de treinamento
        	File trainFile = EvaluateUtils.memoryToFile(bestMem,"resultFSISCoevTrain.txt",st,db,tuples,positions,nBits);
        	double parcialResult = classifier.evaluate(trainFile,trainFile);
        	//Arquivo de Teste
        	File testFile = null;
			//Gera o arquivo de teste
        	if ( testSetOnly ) {
        		/** Daqui para baixo faz apenas 20% **/
        		Database dbTeste = LoadFile.loadDatabase(DATASET_TESTE);
        		testFile = converter.convert(fsGen,SpeciesConstants.FEATURE_SELECTION,"resultFSISCoevTeste.txt",st,dbTeste,tuples,positions);
        	}
        	else {
        		/** Daqui para baixo faz 80% + 20% **/
	        	testFile = EvaluateUtils.memoryToFile(bestMem,"resultFSISCoevTeste.txt",st,db,tuples,positions,nBits);
	        	//Adiciona as linhas no arquivo de teste
	        	converter.addTestData(fsGen,SpeciesConstants.FEATURE_SELECTION,st,DATASET_TESTE,testFile);
        	}        	
        	//Roda o classificador		    
		    double finalResult = classifier.evaluate(trainFile,testFile);
			
			/*
			SharedMemory bestMem = domain.getBest();
			Genotype fsGen = (Genotype)bestMem.getIndividual(SpeciesConstants.FEATURE_SELECTION).getIndividual();
			
		    File file = EvaluateUtils.memoryToFile(bestMem,"resultCoev",st,db);
		    GenotypeConverter converter = new GenotypeConverter();
		    converter.addTestData(fsGen,SpeciesConstants.FEATURE_SELECTION,st,DATASET_TESTE,file);
			
		    WekaClassification classifier = new WekaClassification();
		    double finalResult = classifier.evaluate(file);*/
		    
		    System.out.println("##################################");
		    System.out.println("######### Resultado Geral ########");
		    System.out.println("Fitness Best Ga: "+parcialResult);
		    System.out.println("Fitness Best Ga + Teste: "+finalResult);
		    System.out.println("##################################");
		    
			System.out.println("Arquivo de resultado gerado com sucesso!");
			System.out.println(new Date());		
			
		} catch (InvalidTypeException e) {
			e.printStackTrace();
		} catch (Exception e) {			
			e.printStackTrace();
		}
	}
	
}
